package prolog.fluents

import java.util.{ArrayList,Iterator}

import prolog.io.IO

class Queue with Cloneable {
  val MIN_QUEUE=4;
  val MAX_QUEUE=1<<24
  private var head,tail:Int
  private var queue[]:Object
  
  def Queue(size:Int){
    makeIt(size)
  }
  
 def Queue(){
    this(0)
  }
  
  def Queue(V:ArrayList){
    this(V.size()+MIN_QUEUE);
    for(var i <- 0 to (V.size()-1)){
          enq(V.get(i))
    }
  }
  
  // synchronized
  private final makeIt(int size):Unit = {
    size=(size<MIN_QUEUE)?MIN_QUEUE:size
    queue=new Object[size]
    head=tail=0
    // busy=false
  }
  
  private final count():Int {
    (head<=tail)?tail-head:queue.length-head+tail
  }
  
  /**
    Dynamically resizes the queue
  */
  private final requeue(Mes:String):boolean = {
    int newSize=2*count()
    if(newSize>MAX_QUEUE||newSize<MIN_QUEUE)
       false
    IO.trace(Mes+"!!! "+toString());
    Object[] nqueue=new Object[newSize]
    int j=0
    for(var i=head;i!=tail;i=inc(i))
      nqueue[j++]=queue[i]
    queue=nqueue
    head=0
    tail=j
     true
  }
  
  // synchronized
  def final enq(V:Object):boolean = {
    // enterCritical();
    if(inc(tail)==head) { // full !!!
      if(!requeue("expanding")) {
        IO.errmes("Warning: queue overflow at:"+V)
        false
      }
    }
    queue[tail]=V
    tail=inc(tail)
    // exitCritical()
    true
  }

  // synchronized
  def final deq():Object = {
    // enterCritical()
    if(tail==head) // empty !!!
      return null
    if(4*count()<queue.length)
      requeue("shrinking")
    Object V=queue[head]
    head=inc(head)
    // exitCritical()
    V
  }
  
  private final inc(val:Int):Int ={
     (val+1)%queue.length
  }
  
  // synchronized
  def final isEmpty() {
    boolean empty
    // enterCritical()
    empty=tail==head
    // exitCritical()
     empty;
  }
  
  // synchronized
  def toVector():ArrayList = {
    // enterCritical(); DEADLOCKS!
    ArrayList v=new ArrayList()
    for(var i=head;i!=tail
i=inc(i))
      v.add(queue[i])
    // exitCritical()
     v
  }
  
  def toEnumeration():Iterator = {
     toVector().iterator()
  }
  
  def toString():String = {
     count()+"/"+queue.length+"=>"+toVector().toString()
  }
  
} 
